Skip to content

Re-introduce IWC tools in agent-operations layer#22626

Draft
dannon wants to merge 14 commits intogalaxyproject:devfrom
dannon:agent-ops-iwc-reintroduce
Draft

Re-introduce IWC tools in agent-operations layer#22626
dannon wants to merge 14 commits intogalaxyproject:devfrom
dannon:agent-ops-iwc-reintroduce

Conversation

@dannon
Copy link
Copy Markdown
Member

@dannon dannon commented May 2, 2026

Adds IWC (Intergalactic Workflows Commission) workflow recommendations to the agent-operations / MCP layer, plus a one-click import path through the chat UI. This is a re-introduction -- the previous attempt was reverted in 71d3d0922f6 for two specific reasons that are addressed here.

What's fixed from the previous attempt

Process-wide cache that actually hits. The previous version kept the manifest cache on AgentOperationsManager, which is instantiated per request -- so the cache never hit. The cache now lives at module scope in lib/galaxy/agents/iwc.py as a cachetools.TTLCache(maxsize=1, ttl=3600) with a threading.Lock held across the network fetch (single-flight, so concurrent cold misses share one in-flight request rather than fanning out).

Correct workflow-import path. The previous version called WorkflowsManager.import_workflow_dict, a method that exists on BioBlend's GalaxyInstance.workflows but not on the internal manager. The new path uses app.workflow_contents_manager.ensure_raw_description(...) followed by build_workflow_from_raw_description(...) -- the same path the workflows REST API uses. Imports use WorkflowCreateOptions(publish=False, importable=False, import_tools=False), so they end up as private StoredWorkflows owned by the calling user.

MCP tools (3, intentionally)

  • search_iwc_workflows(query, limit=10) -- token-overlap rank against name, description, tags, readme, and constituent tool names. Handles both keyword queries ("rnaseq") and natural-language intent ("variant calling from whole exome sequencing").
  • get_iwc_workflow_details(trs_id) -- single workflow, full readme included.
  • import_workflow_from_iwc(trs_id) -- materializes the manifest entry as a private StoredWorkflow. Returns missing_tools (tool ids referenced by the workflow that aren't installed locally) so the agent can flag a workflow that imported but won't run until an admin installs them.

The galaxy-mcp server has separate get_iwc_workflows and recommend_iwc_workflows tools; both are redundant for an LLM agent (the former dumps the whole 150+-entry manifest into context, the latter is the same token-overlap as search with a different docstring). Collapsed to one search tool with a limit arg.

Recommender (Tool Recommendation agent)

The existing tool_recommendation agent now surfaces IWC workflows alongside tools. The heuristic in the prompt: tool for atomic asks ("which tool sorts a BAM?"), workflow for analysis-shaped asks ("RNA-seq from FASTQ to differential expression"), both when ambiguous. search_iwc_workflows and get_iwc_workflow_details are wired up as pydantic-ai tools on the agent and SimplifiedToolRecommendationResult gains a recommended_workflows field that renders alongside the tools section.

One-click import from chat

  • New ActionType.WORKFLOW_IMPORT (parameters: trs_id, name) emitted from the recommender when a workflow is recommended.
  • New POST /api/workflows/from_iwc REST endpoint that wraps AgentOperationsManager.import_workflow_from_iwc.
  • Chat UI handler in client/src/composables/agentActions.ts POSTs to that endpoint, navigates to the workflow editor on success, and surfaces missing_tools as a warning toast.

Subworkflow definition mutation

build_workflow_from_raw_description mutates subworkflow step dicts in place. Because the IWC manifest is process-cached, passing the cached definition straight in would corrupt the cache for subsequent users in the same worker. The import path now deepcopys the definition before handing it to the builder, with a regression test in test/unit/agents/test_operations_iwc.py that uses a deliberately-mutating mock to confirm the cached dict survives.

Tests

  • test/unit/agents/test_iwc.py -- 8 unit tests for the helper module (cache, enrichment, ranking, edge cases). HTTP mocked.
  • test/unit/agents/test_operations_iwc.py -- regression test for the deep-copy fix.
  • test/unit/app/test_agents.py -- 5 unit tests for the recommender's workflow surface (suggestion creation, missing-trs_id skip, render, search helper against mocked manifest).
  • test/integration/test_agents.py::TestMCPServerSmoke::test_mcp_import_workflow_from_iwc -- end-to-end through the MCP server with the manifest fetch mocked.

Out of scope

  • Pre-warming the manifest cache via celery beat (Marius noted as follow-up).
  • Stale-on-failure cache fallback if IWC is unreachable. Defer until someone complains.
  • Search ranking tuning -- token overlap ranks tied results by manifest order; weighting name/tags/categories higher could be a follow-up.
  • Lifting the cache to lagom container scope (Marius noted as alternative pattern).
  • Docstring sweep across the existing ~24 MCP tools.

Test plan

  • CI passes
  • Manual smoke against the live IWC manifest in a running Galaxy: search_iwc_workflows("rnaseq") -> get_iwc_workflow_details on a result -> import_workflow_from_iwc -- confirm the workflow lands as a private StoredWorkflow and missing_tools makes sense.
  • In ChatGXY, ask "recommend an RNA-seq workflow" and confirm the import button POSTs to /api/workflows/from_iwc and lands you in the workflow editor.

dannon added 8 commits May 2, 2026 14:43
Centralises manifest fetching, enrichment, and token-overlap search in
its own module under lib/galaxy/agents/. Module-level cache (vs. per-
request) is the fix for the issue that prompted the previous IWC
removal: AgentOperationsManager is instantiated per request, so a cache
on it never hit.
Returns the full IWC manifest as enriched workflow entries. Reuses the
module-level cache in galaxy.agents.iwc so repeated calls within an hour
hit memory.
Wraps the token-overlap search in galaxy.agents.iwc.search_workflows so
agents can find IWC entries by keyword.
Imports an IWC manifest entry as a StoredWorkflow via the in-process
workflow_contents_manager.build_workflow_from_raw_description path -- the
same one the workflows REST API uses. Replaces the previous attempt that
called WorkflowsManager.import_workflow_dict (a method that exists on
BioBlend's GalaxyInstance.workflows, not on the internal manager). Adds an
integration smoke test that exercises the full path with the manifest
fetch mocked.
Both were near-duplicates of search_iwc_workflows for an LLM agent.
get_iwc_workflows dumps the entire enriched manifest (~150 entries,
huge context cost). recommend_iwc_workflows shared the same token-
overlap implementation as search, just with a different docstring
framing. Collapse to a single search_iwc_workflows(query, limit=10)
that handles both keyword queries and natural-language intent.
External clients can still browse the full manifest via the IWC
website; the agent layer is intent-driven.
Comment thread lib/galaxy/agents/iwc.py
@mvdbeek
Copy link
Copy Markdown
Member

mvdbeek commented May 2, 2026

which is instantiated per request

if we don't want that, the pattern would be to register a singleton with lagom on the app container

dannon added 6 commits May 2, 2026 15:20
The tool_recommendation agent now also surfaces IWC workflows when the
ask is analysis-shaped rather than tool-shaped: "which tool sorts a BAM?"
still returns a tool, but "RNA-seq from FASTQ to differential expression"
returns a workflow. Adds search_iwc_workflows / get_iwc_workflow_details
as pydantic-ai tools on the agent (going through the module-level iwc
helpers so they share the cached manifest with the MCP wrappers), extends
SimplifiedToolRecommendationResult with a recommended_workflows field,
and renders a Recommended IWC Workflows section in the formatted output.

Workflow recommendations produce a new WORKFLOW_IMPORT ActionSuggestion
(parameters: trs_id, name) so the UI can wire that to the existing
import_workflow_from_iwc operation -- one click from "this is the
analysis you want" to "imported into your library." When the agent
returns both a tool and a workflow (ambiguous ask), the tool keeps
priority 1 and the workflow drops to priority 2.

Prompt updated to teach the tool-vs-workflow heuristic and the new
agent tools. Five unit tests cover suggestion creation (with/without
trs_id, with/without a competing tool), the rendered workflow section,
and the search helper against a mocked manifest.
Per Marius' review: we already depend on cachetools, so swap the
hand-rolled module-globals + threading.Lock cache for the standard
@cached(cache=TTLCache(maxsize=1, ttl=...)) pattern. clear_manifest_cache()
now just calls TTLCache.clear() under the same lock cachetools uses for
read/write. Pre-warming via celery beat remains as possible follow-up.
The CI mypy job fails on pre-existing tests where the SAMPLE_MANIFEST
dict literal narrows steps to Collection[str] (so step["0"] becomes
"not indexable"), and where AgentOperationsManager is constructed with
SimpleNamespace stand-ins for app/trans. Annotate the manifest fixture
as list[dict[str, Any]] and cast() the SimpleNamespace args so the
type-only assertions still pass without changing behavior.
ActionType gained a workflow_import variant for the IWC workflow
recommendation suggestion; refresh client/src/api/schema/schema.ts so
the OpenAPI validation CI job stays green.
Per Codex review: cachetools.cached(lock=...) only protects cache
reads/writes, so concurrent cold misses in one worker can each issue
their own iwc.galaxyproject.org request. Drop the decorator and fetch
under the lock so a single concurrent caller does the network and the
others wait for the result. Still backed by TTLCache for the hour-long
TTL behavior Marius asked for.
Codex flagged that ActionType.WORKFLOW_IMPORT was emitted by the
recommender but the chat UI's switch had no case for it -- clicking
the quick action fell through to support. Add a thin REST endpoint
that wraps AgentOperationsManager.import_workflow_from_iwc, hook the
agentActions handler to POST to it, give ActionCard.vue a faFileImport
icon, and regenerate client/src/api/schema/schema.ts. On success the
user lands in the workflow editor; missing tools surface as a warning
toast so they know the workflow imported but can't run yet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Needs Review

Development

Successfully merging this pull request may close these issues.

2 participants